from rest_framework import viewsets, status, generics
# from rest_framework.exceptions import PermissionDenied as permDenied
from rest_framework.response import Response

from django.db.models import Count

from oauth2_provider.contrib.rest_framework import TokenHasScope

from .models.cc import CC
from .models.cure import Cure
from .models.summary import Summary
from .models.results import Results
from .models.history import History
from .models.relevant import Relevant
from .models.geninfo import GeneralInfo

from .utils.filters import GenInfoFilter
from .utils.mobile import mobile_save_instance
from .utils.paginations import ReturenPagination
from .utils.validate import update_relevanted_tables
from .utils.validate import validate_perm
from .utils.excel import save_excel_results
from .utils.info import reload_list_in_view
from .utils.search import search_results_view
from .utils.savefile import analyse_excel

from .serializers import GenInfoSerializer, CCSerializer
from .serializers import CureSerializer, HistorySerializer
from .serializers import RelevantSerializer, InfoSerializer
from .serializers import ResultsSerializer, SummarySerializer
from .serializers import CheckedSerializer
from .serializers import DataSerializer, UploadExcelSerializer
from .serializers import SearchSerializer, ChartsSerializer

from .permissions import CheckOptionPermission
from .permissions import MobileClientPermission
from .permissions import get_queryset_perm, cur_info_perm

from .decorators import viewset_decorator


class MobileGeninfoView(viewsets.ModelViewSet):
    ''' mobile web API '''
    permission_classes = [TokenHasScope, CheckOptionPermission, MobileClientPermission]
    required_scopes = ['prj001']
    serializer_class = DataSerializer

    def create(self, request, *args, **kwargs):

        data = request.data.get('data')

        import json
        from json.decoder import JSONDecodeError

        if isinstance(data, str):
            try:
                data = json.loads(data)
            except JSONDecodeError:
                data = data
                return Response(status=status.HTTP_400_BAD_REQUEST,
                                data={'msg': '传递信息无法转化'})

        if not isinstance(data, dict):
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'msg': '传递参数类型错误'})

        try:
            msg = mobile_save_instance(data)
            if not isinstance(msg, bool):
                return Response(status=status.HTTP_400_BAD_REQUEST,
                                data={'msg': msg})
        except Exception as e:
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'msg': '错误信息:%s' % e})

        return Response(status=status.HTTP_200_OK, data={'msg': '信息提交成功'})


class GenInfoView(viewsets.ModelViewSet):
    ''' general info API '''
    permission_classes = [TokenHasScope, CheckOptionPermission]
    required_scopes = ['prj001']
    filter_backends = (GenInfoFilter,)
    pagination_class = ReturenPagination
    search_fields = ['=age', 'serial', 'hospital', 'name']

    def get_paginated_response(self, data):
        if self.action == 'partial_update':
            return None
        else:
            return super().get_paginated_response(data)

    def get_queryset(self):
        return get_queryset_perm(self)

    def get_serializer_class(self):
        if self.action in ['create', 'update']:
            return InfoSerializer
        elif self.action == 'partial_update':
            return CheckedSerializer
        elif self.action == 'retrieve':
            return InfoSerializer
        return GenInfoSerializer

    def partial_update(self, request, *args, **kwargs):

        validate_perm(request)

        pk = kwargs.get('pk', None)

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        checked_status = serializer.data['is_checked']
        checked_reasons = serializer.data.get('reasons_for_not_passing', None)

        if checked_status in ('审核通过', '未审核'):
            checked_reasons = None

        if not pk:
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'msg': '无操作对象'})
        obj = self.get_object()

        if not update_relevanted_tables(obj=obj,
                                        request=request,
                                        checked_status=checked_status,
                                        checked_reasons=checked_reasons):

            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'msg': '审核失败'})

        return Response({'msg': '审核成功'})

    def update(self, request, *args, **kwargs):
        cur_info_perm(self)
        return super().update(request, *args, **kwargs)

    def destroy(self, request, *args, **kwargs):
        cur_info_perm(self)
        return super().destroy(request, *args, **kwargs)


@viewset_decorator(SearchSerializer, GeneralInfo)
class SearchGenInfoView(viewsets.ModelViewSet):
    ''' search info API '''
    pagination_class = ReturenPagination

    def list(self, request, *args, **kwargs):
        req_data = request.data
        # <QueryDict: {'name': ['qw'], 'address': ['上海'], 'telephone': ['1'], 'hospital': ['亿元']}>
        tps = req_data.get('types')
        resp_data_list = list()

        if not req_data:
            sd, page, search_id_list = reload_list_in_view(self, request,
                                                           serializer_own=GenInfoSerializer)
            # -- download file
            if tps == 'download':
                try:
                    file_path = save_excel_results(self,
                                                   request,
                                                   id_list=search_id_list,
                                                   md=GeneralInfo,
                                                   resp_data_list=resp_data_list)
                except Exception as e:
                    return Response(data={'msg': '信息导出失败: %s' % e},
                                    status=status.HTTP_400_BAD_REQUEST)

                return Response({'path': file_path}, status=status.HTTP_200_OK)
            # -- end download
            if page is not None:
                return self.get_paginated_response(sd.get('data'))
            return Response(sd.get('data'))

        resp_data, search_id_list = search_results_view(req_data,
                                                        sf=self,
                                                        obj=GeneralInfo,
                                                        request=request,
                                                        sz=GenInfoSerializer,
                                                        attr_sz=SearchSerializer)
        # -- download file
        if tps == 'download':
            try:
                file_path = save_excel_results(self,
                                               request,
                                               id_list=search_id_list,
                                               md=GeneralInfo,
                                               resp_data_list=resp_data_list)
            except Exception as e:
                return Response(data={'msg': '信息导出失败: %s' % e},
                                status=status.HTTP_400_BAD_REQUEST)

            return Response({'path': file_path}, status=status.HTTP_200_OK)
        # -- end download
        status_ = resp_data.get('status')
        type_ = resp_data.get('type')
        data = resp_data.get('data')

        if status_:
            return Response(resp_data, status=status_)
        if type_ == 'page_serializer':
            return self.get_paginated_response(data)
        if type_ == 'one_serializer':
            return Response(data)
        return Response(resp_data)


@viewset_decorator(CCSerializer, CC, is_not_info='cc')
class CCView(viewsets.ModelViewSet):
    pass


@viewset_decorator(CureSerializer, Cure, is_not_info='cure')
class CureView(viewsets.ModelViewSet):
    pass


@viewset_decorator(SummarySerializer, Summary, is_not_info='summary')
class SummaryView(viewsets.ModelViewSet):
    pass


@viewset_decorator(ResultsSerializer, Results, is_not_info='results')
class ResultsView(viewsets.ModelViewSet):
    pass


@viewset_decorator(HistorySerializer, History, is_not_info='history')
class HistoryView(viewsets.ModelViewSet):
    pass


@viewset_decorator(RelevantSerializer, Relevant, is_not_info='relevant')
class RelevantView(viewsets.ModelViewSet):
    pass


@viewset_decorator(UploadExcelSerializer, 'upload')
class UploadExcelView(viewsets.ModelViewSet):
    ''' upload file API '''

    def create(self, request, *args, **kwargs):
        serializer = UploadExcelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save(owner=request.user)
        try:
            msg = analyse_excel(serializer.validated_data['ivfile'],
                                sf=self,
                                request_param=request)
        except Exception as e:
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'msg': '%s' % e})

        if not msg:
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'msg': '保存失败'})
        return Response(status=status.HTTP_200_OK,
                        data={'msg': msg})


class ChartsView(generics.ListAPIView):
    ''' data analyse API '''
    queryset = GeneralInfo.objects.all()
    serializer_class = ChartsSerializer
    pagination_class = None
    permission_classes = [TokenHasScope, ]
    required_scopes = ['prj001']

    def get(self, request, *args, **kwargs):
        ''' to return data for echarts '''
        resp_data = {}

        all_obj_list = self.get_queryset()

        checked_choice = GeneralInfo.CHECKED_CHOICE

        checked_status = [status[0] for status in checked_choice]

        resp_data['checked_status'] = checked_status

        resp_data['pine'] = []
        resp_data['bar'] = []

        # pine
        for ix, st in enumerate(checked_status):
            pine_num_of_status = all_obj_list.filter(is_checked=st).count()

            name_value = {
                'name': st,
                'value': pine_num_of_status
            }

            resp_data['pine'].append(name_value)

        # bar
        hospital_of_user_id = GeneralInfo.objects.select_related('owner').\
            values('owner__hospital').\
            annotate(hospital_count=Count('owner__hospital')).\
            order_by('-hospital_count')

        hospital_list = []

        for hospital_value in hospital_of_user_id:
            hospital_list.append(hospital_value.get('owner__hospital'))

        resp_data['hospitals_list'] = hospital_list

        for st in checked_status:
            series_value = {
                'name': st,
                'data': []
            }

            for hs in hospital_list:
                bar_num_status = all_obj_list.filter(owner__hospital=hs).\
                    filter(is_checked=st).\
                    count()

                series_value['data'].append(bar_num_status)

            resp_data['bar'].append(series_value)

        return Response({'data': resp_data})
